#include <cppunit/extensions/HelperMacros.h>
#include <cppunit/config/SourcePrefix.h>
#include "udk.h"
#include "udktest_os.h"
#include "udk_os.h"

// Registers the fixture into the 'registry'
CPPUNIT_TEST_SUITE_REGISTRATION( UDKOsTest );

void 
UDKOsTest::setUp()
{
}


void 
UDKOsTest::tearDown()
{
}

static int testparam=0;
static int testthread_entry1(void* p)
{
  if(NULL!=p)
    testparam = (int)p;
  udk_msleep(1000);
  return 0;
}

class MyTestThread:public Thread
{
public:
  MyTestThread(int stuff=0,int loopend=0):Thread(true){
     m_teststuff = stuff;
     m_loopend = loopend;   
  }
  status_t    readyToRun(){
     return NO_ERROR;
  }
private:
  
  bool threadLoop()
  {
    udk_msleep(5);
    m_teststuff++;
    if(m_loopend) 
	return false;
    else
	return true;
  }
  public:
    int m_teststuff;
    int m_loopend;
};
void UDKOsTest::testThread()
{
  bool ret = createThread(testthread_entry1,NULL);
  CPPUNIT_ASSERT(true==ret);
  createThread(testthread_entry1,(void*)1);
  udk_msleep(100);
  CPPUNIT_ASSERT(testparam!=0);
  MyTestThread* mythread = new MyTestThread(0,0);
  CPPUNIT_ASSERT(mythread!=NULL);
  CPPUNIT_ASSERT(mythread->m_teststuff==0);
  CPPUNIT_ASSERT(mythread->run()==NO_ERROR);
  CPPUNIT_ASSERT(mythread->run()!=NO_ERROR);//2nd run should be failed 
  udk_msleep(100);
  CPPUNIT_ASSERT(mythread->m_teststuff>0);
  CPPUNIT_ASSERT(mythread->requestExitAndWait()==NO_ERROR);
  mythread->m_loopend++;
  CPPUNIT_ASSERT(mythread->run()==NO_ERROR);
  udk_msleep(100);
  CPPUNIT_ASSERT(mythread->requestExitAndWait()==NO_ERROR);
  delete mythread;
}

void UDKOsTest::testMutex()
{
  Mutex* mymtx = new Mutex();
  CPPUNIT_ASSERT(mymtx->lock()==NO_ERROR);
  mymtx->unlock();
  CPPUNIT_ASSERT(mymtx->lock()==NO_ERROR);
  CPPUNIT_ASSERT(mymtx->tryLock()!=NO_ERROR);
  mymtx->unlock();
  CPPUNIT_ASSERT(mymtx->tryLock()==NO_ERROR);
  mymtx->unlock();
  {
    AutoMutex lock(mymtx);
    CPPUNIT_ASSERT(mymtx->tryLock()!=NO_ERROR);
  }
  CPPUNIT_ASSERT(mymtx->tryLock()==NO_ERROR);
  mymtx->unlock();
  delete mymtx;
}

class MyConditionTestThread:public Thread
{
public:
    MyConditionTestThread(int stuff=0,int loopend=0):Thread(true){
     m_teststuff = stuff;
     m_loopend = loopend;
     m_waitok = 0;  
  }
  status_t    readyToRun(){
     return NO_ERROR;
  }
  void SetWaitCondition(int waitok=0){
     m_waitok = waitok;
  }
  status_t WaitCondition(){
    return mThreadTestCondition.wait(mLock);
  }
  status_t WaitConditionRelative(nsecs_t reltime){
    return mThreadTestCondition.waitRelative(mLock,reltime);
  }
  void SignalCondition(){
	mLock.lock();	
	mThreadTestCondition.signal();
	mLock.unlock(); 
  }

private:
  
  bool threadLoop()
  {
    udk_msleep(1);
    m_teststuff++;
    AutoMutex lock(&mAccessLock);
    {
      if(1==m_waitok){
	mLock.lock();	
	mThreadTestCondition.signal();
	mLock.unlock();
      }else if(2==m_waitok){
	mLock.lock();	
	mThreadTestCondition.broadcast();
	mLock.unlock();      
      }else if(3==m_waitok){
	m_result=WaitConditionRelative(100000);
      }else if(4==m_waitok){
	m_result=WaitCondition();
      }
    }
    if(m_loopend) 
	return false;
    else
	return true;
  }
  public:
    int m_teststuff;
    int m_loopend;
    int m_waitok;
    int m_result;
    Mutex           mLock;
    Mutex	    mAccessLock;
    Condition       mThreadTestCondition;
};
void UDKOsTest::testCondition()
{
  MyConditionTestThread tcthread;
  CPPUNIT_ASSERT(tcthread.WaitConditionRelative(100000)!=NO_ERROR);
  tcthread.run();
  {
	AutoMutex lock(&tcthread.mAccessLock);
  	tcthread.SetWaitCondition(1);
  }
  CPPUNIT_ASSERT_EQUAL(tcthread.WaitCondition(),NO_ERROR);
  {
	AutoMutex lock(&tcthread.mAccessLock);
  	tcthread.SetWaitCondition(1);
  }
  CPPUNIT_ASSERT_EQUAL(tcthread.WaitConditionRelative(100000000),NO_ERROR);
  {
	AutoMutex lock(&tcthread.mAccessLock);
  	tcthread.SetWaitCondition(2);
  }
  CPPUNIT_ASSERT_EQUAL(tcthread.WaitCondition(),NO_ERROR);
  {
	AutoMutex lock(&tcthread.mAccessLock);
  	tcthread.SetWaitCondition(2);
  }
  CPPUNIT_ASSERT_EQUAL(tcthread.WaitConditionRelative(100000000),NO_ERROR);
  {
	AutoMutex lock(&tcthread.mAccessLock);
	CPPUNIT_ASSERT(tcthread.WaitConditionRelative(100000000)!=NO_ERROR);
  }
  {
	AutoMutex lock(&tcthread.mAccessLock);
	tcthread.SetWaitCondition(3);
	tcthread.m_result=NO_ERROR;
  }
  udk_msleep(10);
  CPPUNIT_ASSERT(tcthread.m_result!=NO_ERROR);
  {
	AutoMutex lock(&tcthread.mAccessLock);
	tcthread.SetWaitCondition(4);
	tcthread.m_result=~NO_ERROR;
  }
  udk_msleep(10);
  CPPUNIT_ASSERT(tcthread.m_result!=NO_ERROR);
  tcthread.SignalCondition();
  udk_msleep(10);
  CPPUNIT_ASSERT(tcthread.m_result==NO_ERROR);
}




